#!/bin/bash

# vmwarebackup, to back up vmware instances using rsync.
# Copyright (C) 2008 Rene Geers (rene.geers@gmail.com) and Bjoern Remseth (la3lma@gmail.com)
# 
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
# 
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

#
# Important programs we are using.
#
unset PATH
VMWARECMD="/usr/bin/vmware-cmd"
RSYNC=/usr/bin/rsync
RM=/bin/rm
GREP=/bin/grep
ECHO=/bin/echo
TOUCH=/usr/bin/touch
SUDO=/usr/bin/sudo
SSH=/usr/bin/ssh
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
RSYNCOPTS="--rsync-path=/raid0/data/module/RSYNC/system/bin/rsync -avze ssh"

#
# Directories we care about
#
IPDB=/data/etc/VMS
VMDIR=/data/vm
DESTDIR=/data/backup
DESTINATION=193.156.19.120:/raid0/data/usbhdd/Users/rene/backup
LOCKFILE=/data/etc/Backingupnow
POSITIONFILE=/data/etc/Position
#We do not want to have a running backup during the daytime. 
STOPTIME=0700

#
# Debugmode: Sett the variable DEBUG for debugging this script
#
#DEBUG=1
if [ $DEBUG ]; then
   $ECHO "Debugmode"
   RUN=0
else
   $ECHO "This script will take all your virtual machines down, and creates a backup on $DESTDIR !!"
   $ECHO ""
   $ECHO "Press Ctrl-C now if you did not intent this"
   sleep 1
   RUN=1
fi



#Check for a runnning backup  first
#Remove the lock if this scripts exits
trap "{ $RM -f $LOCKFILE ; exit 1; }" EXIT
if [ -f "$LOCKFILE" ]; then
   $ECHO "Backup delayed to next run because of pending jobb"
   exit 1
else
   $TOUCH $LOCKFILE
fi

#We save the position where the backup stopped here
if [ -f $POSITIONFILE ]; then
   POSITION=`cat $POSITIONFILE`
   $RM -f $POSITIONFILE
fi

VMS=`$VMWARECMD -l`
IFS=$'\x0A'$'\x0D' # Line Separator for $VMS
for VM in $VMS; do
   #TODO: Not a good expression, but works in our case. It uses field 1-4 of the registered virtual machines.
   VMDIR=`$ECHO $VM|cut -d"/" -f1-4`
   if [ -n "$POSITION" ]; then
      if [ "$VMDIR" != "$POSITION" ];then
         $ECHO skipping $VM to $POSITION...
         continue
      else
         unset POSITION
      fi
   fi
   OS=`$GREP OS "$VM"|cut -d " " -f 3|sed s/\"//g`
   if [ ${OS:0:3} = "win" ]; then
     OS=WIN
   else
     OS=LIN
   fi
   if [ $DEBUG ]; then
       $ECHO $VM $OS
   fi

   NOW=`date +%H%M`
   echo "NOW= $NOW"
   if [ $NOW -gt $STOPTIME ]; then
      $ECHO "Its time to stop this $NOW"
      $ECHO "Saving position $VM to next run"
      $ECHO $VMDIR > $POSITIONFILE
      break 
   fi

   IP=`$GREP $VM $IPDB|cut -d" " -f 1`
   STATE=`$SUDO $VMWARECMD "$VM" getstate`
   ON="getstate() = on"
   $ECHO $VM $STATE $IP
   if [ "$STATE" = "$ON" -a "$IP" != "SKIP" ]; then
      if [ "$OS" = "WIN" ]; then
         $ECHO "$SUDO $VMWARECMD $VM stop"
         if [ $RUN ]; then
	   $SUDO $VMWARECMD "$VM" stop
         fi
      else
	 if [ "$IP" = "NAT" ]; then
	    $ECHO "Warning: This VM cannot be stopped before the IP is registered in $IPDB!"
	    $ECHO "Warning: Your backup now contains a dirty backup of this machine"
         else
            $ECHO "executing: $SSH $IP $SUDO halt"
            if [ $RUN ]; then
	      $SSH $IP $SUDO halt
            fi
         fi
      fi

      #Bring the VM down controlled first, but hard after a period 
      A=0
      while [ "`$VMWARECMD $VM getstate`" = "$ON" ]; do
	$ECHO "Sleeping..."
        A=$(($A+1))
	if [ $A = "10" ]; then
           $ECHO "Stopping the virtuall machine the hard way"
           $ECHO "$SUDO $VMWARECMD $VM stop hard"
           if [ $RUN ]; then
	     $SUDO $VMWARECMD "$VM" stop hard
           fi
	   break
	fi
	sleep 9
      done

      #Take the backup
      $ECHO $SUDO $RSYNC -av $VMDIR $DESTDIR
      if [ $RUN ]; then
	 $SUDO $RSYNC -av $VMDIR $DESTDIR
	 $SUDO $VMWARECMD "$VM" start
      fi
   fi

done

$ECHO "backup done, syncing disk remote"
$ECHO "$SUDO $RSYNC $RSYNCOPTS $DESTDIR $DESTINATION"
if [ $RUN ]; then
  $SUDO $RSYNC $RSYNCOPTS $DESTDIR $DESTINATION 
   NOW=`date +%H%M`
   echo "NOW= $NOW"
fi
$RM -f $LOCKFILE
